home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / fish / 001-100 / 001-025 / 020 / porthandler / porthandler.asm < prev    next >
Assembly Source File  |  1995-03-17  |  13KB  |  462 lines

  1.     TTL    "Port-Handler AmigaDos Device Driver"
  2. * Port-handler AmigaDos Device Driver
  3. * Copyright (c) 1986 John A. Toebes, VIII   All Rights Reserved
  4. *
  5. * Permission is granted for personal usage only.
  6. * This program may not be incorporated in any commercial product or sold
  7. * for any purpose without the permission of the author.
  8. *
  9.         SECTION    CODE
  10. StartModule    DC.L    (EndModule-StartModule)/4
  11. EntryPt        EQU    *
  12. *
  13.     NOLIST
  14.     INCLUDE    "exec/types.i"
  15.     INCLUDE    "exec/libraries.i"
  16.     INCLUDE    "exec/io.i"
  17.     INCLUDE    "libraries/dosextens.i"
  18.     LIST
  19.     INCLUDE "bcpl.i"
  20. ***
  21. ***    Global constants used
  22. ***
  23. FALSE    EQU    0
  24. TRUE    EQU    -1
  25. IOB_size    EQU    30
  26. RAW_NAME    EQU    ('R'<<24)!('A'<<16)!('W'<<8)
  27. MARKER1_DATA    EQU    ('T'<<24)!('O'<<16)!('P'<<8)!('!')
  28. MARKER2_DATA    EQU    ('J'<<24)!('O'<<16)!('H'<<8)!('N')
  29.  
  30. ***
  31. ***    This is the global structure that we get a pointer to in A1
  32. ***    when our code is executing
  33. ***
  34.     STRUCTURE    PORT_HANDLER_GLOBALS,0
  35.     LONG    IO_parm_pkt        *Pointer to our initial packet
  36. *    LONG    MARKER1
  37. *    LONG    EXECLIB
  38. *    LONG    OURCODE
  39. *    LONG    DOSCALL
  40. *    LONG    DOSRET
  41.     LONG    read_pkt        *Pointer to user read request
  42.     LONG    write_pkt        *Pointer to user write request
  43.     BYTE    openin            *device is open for input
  44.     BYTE    openout            *device is open for output
  45.     WORD    FILLER            * to pad to a 4 byte boundary
  46.     BPTR    node            *pointer to our DeviceList node
  47.     BPTR    inpkt            *pointer to read transmission pkt
  48.     STRUCT    inpkt_buf,16        * Buffer for above
  49.     BPTR    outpkt            *pointer to write transmission pkt
  50.     STRUCT    outpkt_buf,16        * Buffer for above
  51.     BPTR    IOB            *IO request for reading from device
  52.     STRUCT    IOB_buf,(IOB_size*4)+8    * Buffer for above
  53.     BPTR    IOBO            *IO request for writing to device
  54.     STRUCT    IOBO_buf,(IOB_size*4)+8    * Buffer for above
  55.     APTR    dataloc            *QUE pointer-data to be written/read
  56.     BPTR    tpkt            *QUE pointer-IO completion msg packet
  57.     BPTR    use_IOB            *QUE pointer-IOB for IO
  58. *    LONG    MARKER2
  59.     BPTR    FILLER1
  60.     LABEL    FRAME_SIZE
  61. *
  62. * This routine is a sample device handler for
  63. *    SER:    The serial port
  64. *    PAR:    The parallel port
  65. *    PRT:    The installed printer
  66. *    PRT:RAW    The installed printer without translating LF to CR
  67. *
  68.  
  69. * BCPL driver Entry conditions:
  70. *    D1 - DosPacket - immediately converted to a real pointer
  71. *    A0 - 0
  72. *    A1 - Pointer to our global data area
  73. *    A2 - Pointer to BCPL subroutine library
  74. *    A3 - <Unassigned>
  75. *    A4 - Pointer to Base of out code
  76. *    A5 - Pointer to Subroutine transfer vector
  77. *    A6 - Pointer to Code termination vector
  78. *
  79.  
  80. * Upon initialization, D1 contains a BPTR to a DosPacket with the info:
  81. *    arg1 = BPTR to BCPL string of device name
  82. *        This is should be one of PRT: PRT:RAW SER: PAR:
  83. *    arg2 = Extra info from the DevList entry.
  84. *        0 = SER:    1 = PAR:    2 = PRT:
  85. *    arg3 = BPTR to the DevList entry
  86. *
  87.     LSL.L    #2,D1        *make pointer to DosPacket real
  88.  
  89. *    Initialize our global structure
  90. *    MOVE.L    A1,$CA
  91. *    MOVE.L    #MARKER1_DATA,MARKER1(A1)    *let us see it in memory
  92. *    MOVE.L    #MARKER2_DATA,MARKER2(A1)
  93. *    MOVE.L    A2,EXECLIB(A1)
  94. *    MOVE.L    A4,OURCODE(A1)
  95. *    MOVE.L    A5,DOSCALL(A1)
  96. *    MOVE.L    A6,DOSRET(A1)
  97.     CLR.L    read_pkt(A1)    *No Read request pending
  98.     CLR.L    write_pkt(A1)    *No write request pending
  99.     CLR.B    openin(A1)    *device not opened for input
  100.     CLR.B    openout(A1)    *device not opened for output
  101.     MOVE.L    dp_Arg3(A0,D1.L),D3
  102.     LSL.L    #2,D3        *make it a real pointer
  103.     MOVE.L    D3,node(A1)    *to our DevList entry
  104.  
  105.     MOVEQ.L    #inpkt_buf,D3    *locate our default input packet
  106.     ADD.L    A1,D3
  107.     MOVE.L    #act_queueread,dp_Type(A0,D3.L)    *and set it as a read packet
  108.     LSR.L    #2,D3
  109.     MOVE.L    D3,inpkt(A1)
  110.  
  111.     MOVEQ.L    #outpkt_buf,D4    *locate our default output packet
  112.     ADD.L    A1,D4
  113.     MOVE.L    #act_queuewrite,dp_Type(A0,D4.L) *and set as write packet
  114.     LSR.L    #2,D4
  115.     MOVE.L    D4,outpkt(A1)
  116.  
  117.     MOVEQ.L    #IOB_buf,D5    *locate our input IO request packet
  118.     ADD.L    A1,D5
  119.     LSR.L    #2,D5
  120.     MOVE.L    D5,IOB(A1)
  121.  
  122.     MOVE.L    #IOBO_buf,D6    *locate our output IO request packet
  123.     ADD.L    A1,D6
  124.     LSR.L    #2,D6
  125.     MOVE.L    D6,IOBO(A1)
  126.  
  127.     MOVEQ.L    #IOB_size-1,D5    *Empty our input IOB
  128.     LEA    IOB_buf(A1),A3
  129. CLRIOB    CLR.L    (A3)+
  130.     DBF    D5,CLRIOB
  131.  
  132. ***    Open the device
  133. ***    We have to figure out what device we will be opening
  134.     MOVEQ.L    #0,D4        * Flags on the open
  135.     MOVE.L    D4,D3        * Unit number
  136.  
  137.     TST.L    dp_Arg2(A0,D1.L)    * is it a open on SER:
  138.     BEQ    IS_SER
  139.     MOVEQ.L    #1,D2
  140.     CMP.L    dp_Arg2(A0,D1.L),D2    * is it an open on PAR:
  141.     BEQ    IS_PAR
  142.  
  143. IS_PRT    LEA    prt_name(A4),A3        PRT: uses printer.device
  144.     BRA    PUTNAME
  145.  
  146. IS_SER    LEA    ser_name(A4),A3        SER: uses serial.device
  147.     BRA    PUTNAME
  148.  
  149. IS_PAR    LEA    par_name(A4),A3        PAR: uses parallel.device
  150. PUTNAME    EQU    *
  151.     MOVE.L    A3,D2
  152.     LSR.L    #2,D2        *make the name a BPTR
  153.     MOVE.L    IOB(A1),D1
  154.     BCALL    OpenDevice
  155.  
  156.     TST.L    D1        *did the open succeed
  157.     BNE    GOTOPEN        *no...
  158.  
  159.     MOVE.L    #ERROR_OBJECT_IN_USE,D3    *say it is in use
  160.     MOVEQ.L    #FALSE,D2
  161.     MOVE.L    (A1),D1
  162.     BCALL    returnpkt
  163.     BEXIT
  164.  
  165. GOTOPEN    EQU    *
  166.  
  167.     MOVEQ.L    #IOB_size-1,D5    *get a second IOB for output
  168.     LEA    IOB_buf(A1),A3
  169.     LEA    IOBO_buf(A1),A0    *Use only for copying - restore to 0 later
  170. COPYIOB    MOVE.L    (A3)+,(A0)+
  171.     DBF    D5,COPYIOB
  172.     MOVEQ.L    #0,D5
  173.     MOVE.L    D5,A0
  174.  
  175. ***    Now see if they asked to put the printer into the RAW mode
  176.     MOVE.L    (A1),D1
  177.     LSL.L    #2,D1
  178.     MOVEQ.L    #2,D5
  179.     CMP.L    dp_Arg2(A0,D1.L),D5    * is it a open on PRT:
  180.     BNE    NOTRAW
  181.     MOVE.L    dp_Arg1(A0,D1.L),D3
  182.     LSL.L    #2,D3
  183.     CMP.L    #RAW_NAME,4(A0,D3.L)    *is the secondpart 'RAW\0'?
  184.     BNE    NOTRAW
  185.  
  186. ***    Build the IOB for outputing the initialization string
  187.     LEA    prt_init_str(A4),A3        *point to the output string
  188.     MOVE.L    A3,D3
  189.     MOVE.L    IOBO(A1),D1
  190.     ASL.L    #2,D1
  191.     MOVE.L    D1,A3
  192.     MOVE.W    #CMD_WRITE,D2
  193.     MOVE.L    D2,IO_COMMAND(A3)    ;$1C
  194.     MOVE.L    D3,IO_DATA(A3)        ;$28
  195.     MOVEQ.L    #-1,D4
  196.     MOVE.L    D4,IO_LENGTH(A3)    ;$24
  197.  
  198.     MOVE.L    IOBO(A1),D1    *DOIO(IOBO) to output the init string
  199.     BCALL    DoIO
  200.  
  201. NOTRAW    EQU    *
  202.  
  203. ***    set taskid field to our task so everyone comes to us for the device
  204.     BCALL    taskid
  205.     MOVE.L    node(A1),D2
  206.     MOVE.L    D1,dl_Task(A0,D2.L)
  207.  
  208. ***    We are now setup, return our initilization packet so we can
  209. ***    Let the system start sending us IO requests
  210.     MOVEQ.L    #TRUE,D2
  211.     MOVE.L    (A1),D1        IO_parm_pkt
  212.     BCALL    returnpkt
  213.  
  214. ***    Now that all the initialization is done, here is where we do all
  215. ***    the work of processing the requests.  Of importance to note is that
  216. ***    although we have opened the device, the real request to open the
  217. ***    device comes (usually) as the first message to our task.
  218. ***
  219. ***    Events come to us in the form of a DosMessage with the type of
  220. ***    event in the type field of the packet
  221. ***    We only need to handle a few of these events and can just send
  222. ***    the rest back as invalid requests
  223. ***
  224. ***    The ones we handle are:
  225. ***    'R'    - A request to read from the device
  226. ***    'W'    - A request to write to a device
  227. ***    1001    - A read WE posted to the device completed
  228. ***    1002    - A write WE posted to the device completed
  229. ***    1005    - The user wishes to open the device we handle for input
  230. ***    1006    - The user wishes to open the device we handle for output
  231. ***    1007    - The uses wishes to terminate an open on our device
  232. ***
  233. ***    Register usage:
  234. ***    D1 - BCPL pointer to event message packet
  235. ***    D2 - real pointer to event message packet - until changed
  236. ***
  237. ***    Wait for the next message
  238. LOOP    EQU    *
  239.     BCALL    taskwait
  240.     MOVE.L    D1,D2
  241.     LSL.L    #2,D2
  242.  
  243. ***    Now see what type of message it was
  244.     MOVE.L    dp_Type(A0,D2.L),D3
  245.  
  246.     MOVEQ.L    #'R',D4
  247.     CMP.L    D4,D3        *read
  248.     BEQ    do_R
  249.  
  250.     MOVEQ.L    #'W',D4
  251.     CMP.L    D4,D3        *write
  252.     BEQ    do_W
  253.  
  254.     CMP.L    #act_queueread,D3    *act.read
  255.     BEQ    do_read
  256.  
  257.     CMP.L    #act_queuewrite,D3    *act.write
  258.     BEQ    do_writ
  259.  
  260.     CMP.L    #act_findinput,D3    *find input
  261.     BEQ    do_old
  262.  
  263.     CMP.L    #act_findoutput,D3    *find output
  264.     BEQ    do_new
  265.  
  266.     CMP.L    #act_end,D3    *end
  267.     BEQ    do_end
  268.  
  269.     BRA    do_dflt
  270.  
  271. *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  272. ***
  273. ***    Open up our device for input
  274. ***
  275. *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  276. do_old    TST.B    openin(A1)    *make sure it isn't already open for input
  277.     BNE    IN_USE
  278.  
  279.     ST    openin(A1)    *Say we have the device for input
  280.     MOVE.L    #MODE_OLDFILE,D3
  281.     BRA    SET_SCB
  282.  
  283. *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  284. ***
  285. ***    Open up our device for output
  286. ***
  287. *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  288. do_new    TST.B    openout(A1)
  289.     BNE    IN_USE
  290.  
  291.     ST    openout(A1)    *Say we have the device for output
  292.     MOVE.L    #MODE_NEWFILE,D3
  293.  
  294. SET_SCB    MOVE.L    dp_Arg1(A0,D2.L),D4
  295.     LSL.L    #2,D4
  296.     MOVE.L    D3,fh_Arg1(A0,D4.L)    *and set the access mode
  297.     MOVEQ.L    #TRUE,D5
  298.     MOVE.L    D5,fh_Interactive(A0,D4.L)    * Mark file as interactive
  299.     BRA    OK_RET
  300.  
  301. *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  302. ***
  303. ***    Close the device for input/output
  304. ***
  305. *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  306. do_end    CMP.L    #MODE_OLDFILE,dp_Arg1(A0,D2.L)
  307.     BNE    closout
  308.     CLR.B    openin(A1)    *device no longer needed for input
  309.     BRA    doclose
  310. closout    CLR.B    openout(A1)    *device no longer needed for output
  311. doclose    EQU    *
  312.  
  313. ***    If this closed both files then it is time to shut down
  314.     TST.B    openin(A1)
  315.     BNE    OK_RET
  316.     TST.B    openout(A1)
  317.     BNE    OK_RET
  318.     MOVE.L    node(A1),D3    *find our devicelist entry
  319.     CLR.L    dl_Task(A0,D3.L) *remove our process id from the entry
  320.     BRA    OK_RET
  321.  
  322. *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  323. ***
  324. ***    Here we have a read request we posted returning to us
  325. ***
  326. *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  327. do_read    MOVE.L    D1,inpkt(A1)    *restore our packet for posting reads
  328.  
  329.     MOVE.L    read_pkt(A1),D1    *the message to return to the user
  330.     LEA    IOB_buf(A1),A3    *the IO request that returned
  331.     BRA    CHK_RET
  332.  
  333. *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  334. ***
  335. ***    Here we have a write request we posted returning to us
  336. ***
  337. *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  338. do_writ    MOVE.L    D1,outpkt(A1)    *restore out packet for posting writes
  339.  
  340.     MOVE.L    write_pkt(A1),D1    *the message to return to the user
  341.     LEA    IOBO_buf(A1),A3        *the IO request that returned
  342.  
  343. CHK_RET    MOVEQ.L    #0,D3
  344.     MOVE.B    IO_ERROR(A3),D3        *get the error code if any
  345.     BNE    BAD_RET            *any error?
  346.     MOVE.L    IO_ACTUAL(A3),D2    *return number of bytes read
  347.     BRA    RET_PKT
  348.  
  349. *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  350. ***
  351. ***    Here we have a request from the user to do a read
  352. ***
  353. *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  354. do_R    MOVE.L    D1,read_pkt(A1)
  355.     MOVE.L    inpkt(A1),tpkt(A1)
  356.     CLR.L    inpkt(A1)        *Indicate input in progress
  357.  
  358.     MOVEQ.L    #CMD_READ,D4
  359.     MOVE.L    IOB(A1),D1
  360.  
  361.     BRA    QUE_PKT
  362.  
  363. *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  364. ***
  365. ***    Here we have a request from the user to do a write
  366. ***
  367. *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  368. do_W    MOVE.L    D1,write_pkt(A1)
  369.     MOVE.L    outpkt(A1),D3
  370.     CLR.L    outpkt(A1)    *Indicate an output is in progress
  371.  
  372.     MOVEQ.L    #CMD_WRITE,D4
  373.     MOVE.L    IOBO(A1),D1
  374.  
  375. ***    To queue an IO request we need to have set up:
  376. ***    D1 - BCPL pointer to the desired IOB
  377. ***    D2 - The real pointer to the input request message
  378. ***    D3 - message packet associated with the request
  379. ***    D4 - I/O request type to be queued
  380. QUE_PKT    MOVE.L    D1,D5
  381.     ASL.L    #2,D5
  382.     MOVE.L    D5,A3
  383.  
  384.     MOVE.W    D4,IO_COMMAND(A3)        ;$1C
  385.     MOVE.L    dp_Arg2(A0,D2.L),IO_DATA(A3)    ;$28
  386.     MOVE.L    dp_Arg3(A0,D2.L),IO_LENGTH(A3)    ;$24
  387.     CLR.L    IO_OFFSET(A3)            ;$28
  388.  
  389.     MOVE.L    D3,D2
  390.     BCALL    SendIO
  391.     BRA    LOOP
  392.  
  393. *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  394. ***
  395. ***    Here we handle all other requests we do not recognize
  396. ***
  397. *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  398. do_dflt    TST.B    openin(A1)
  399.     BNE    BAD_ACT
  400.     TST.B    openout(A1)
  401.     BNE    BAD_ACT
  402.     MOVE.L    node(A1),D1    *keep them from bothering us anymore
  403.     CLR.L    dl_Task(A0,D1.L)
  404. BAD_ACT    EQU    *
  405.     MOVE.L    #ERROR_ACTION_NOT_KNOWN,D3
  406.     BRA    BAD_RET
  407.  
  408. ***
  409. ***    Here we return the message to the user
  410. ***
  411. IN_USE    MOVE.L    #ERROR_OBJECT_IN_USE,D3    *the device is in use
  412. BAD_RET    MOVEQ.L    #FALSE,D2    *Operation had failed
  413.     BRA    RET_PKT
  414. OK_RET    MOVEQ.L    #TRUE,D2    *Operation has succeeded
  415. RET_PKT    BCALL    returnpkt    *D1 already has the packet address in it
  416.  
  417. LOOPIT    TST.B    openin(A1)    *is there anyone open on us?
  418.     BNE    LOOP
  419.     TST.B    openout(A1)
  420.     BNE    LOOP
  421.     TST.L    outpkt(A1)    *or an output pending?
  422.     BEQ    LOOP
  423.     TST.L    inpkt(A1)    *or an input pending?
  424.     BEQ    LOOP
  425.  
  426. ***
  427. ***    Our purpose in life is fullfilled, close the device
  428. ***    and quietly fade off into the sunset
  429. ***
  430.     MOVE.L    IOB(A1),D1
  431.     BCALL    CloseDevice
  432.     BEXIT
  433.  
  434.         CNOP    0,4
  435. ser_name    EQU    *-EntryPt
  436.         DC.B    14,'serial.device',0
  437.  
  438.         CNOP    0,4
  439. par_name    EQU    *-EntryPt
  440.         DC.B    16,'parallel.device',0
  441.  
  442.         CNOP    0,4
  443. prt_name    EQU    *-EntryPt
  444.         DC.B    15,'printer.device',0
  445.  
  446.         CNOP    0,4
  447. prt_init_str    EQU    *-EntryPt
  448.         DC.B    $1B,'[20l',0
  449. ***
  450. ***    Trailer stuff to make this look like a BCPL module
  451. ***
  452.         CNOP    0,4
  453.         DC.L    0
  454.         DC.L    1
  455.         DC.L    EntryPt-StartModule
  456.         DC.L    (FRAME_SIZE/4)+2+$44
  457. EndModule    EQU    *
  458.         END
  459.  
  460.  
  461.  
  462.